package com.wallet.my.service.impl;

import com.wallet.my.contract.Web3jContract.PaiMai;
import com.wallet.my.controller.model.TransContractRequest;
import com.wallet.my.dao.mapper.ContractMapper;
import com.wallet.my.dao.mapper.ContractRecordMapper;
import com.wallet.my.dao.pojo.ContractDO;
import com.wallet.my.dao.pojo.ContractRecordDO;
import com.wallet.my.service.ContractService;
import com.wallet.my.service.ListenerService;
import com.wallet.my.util.ContractUtil;
import com.wallet.my.util.EthUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthTransaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.utils.Convert;

import java.io.IOException;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 合约接口实现类
 **/
@Service
public class ContractServiceImpl implements ContractService {
    @Autowired
    private Web3j web3j;                                               //加载初始化后的web3j对象，已经配置测试网kovan连接点
    @Autowired
    private EthUtil ethUtil;
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private ContractRecordMapper contractRecordMapper;
    @Autowired
    private ContractUtil contractUtil;
    @Autowired
    private ListenerService listenerService;

//    查询已发布的所有拍卖合约
    @Override
    public List<ContractDO> getPaiMaiContracts() {
        contractUtil.updataPaiMaiContracts(web3j);         //更新所有拍卖合约的状态和最高出价信息
        List<ContractDO> paiMaiContracts = contractMapper.getPaiMaiContracts();
        return paiMaiContracts;
    }

    //    部署合约
    @Override
    public Map<String, Object> newPaiMaiContract(TransContractRequest transContractRequest) {
        String privateKey = transContractRequest.getPrivateKey();
        Credentials credentials = Credentials.create(privateKey);
        //获取全网平均gasprice
        BigInteger gasPrice = ethUtil.getMyGasPrice(web3j);
        BigInteger gasLimit = new BigInteger(transContractRequest.getGasLimit());
        BigInteger _biddingTime = new BigInteger(transContractRequest.get_biddingTime());
        String _beneficiary = transContractRequest.get_beneficiary();
//        部署一个拍卖合约，输入持续时间秒，   卖方地址
        PaiMai newPaiMai=null;
        try {
            newPaiMai = PaiMai.deploy(web3j, credentials, gasPrice, gasLimit, _biddingTime, _beneficiary).send();
        } catch (Exception e) {
            e.printStackTrace();
        }
        HashMap<String, Object> map = new HashMap<>();
        if (newPaiMai==null){
            map.put("code", "1");
            map.put("message", "error");
        }else {
            // 开启监听交易，最高出价更新时
//            paiMai.highestBidIncreasedEventFlowable(DefaultBlockParameter.valueOf(startBlockNumber), DefaultBlockParameterName.LATEST);
            String contractAddress = newPaiMai.getContractAddress();
            System.out.println(contractAddress);
            map.put("code", "200");
            map.put("message", "ok");
            map.put("contractAddress", contractAddress);
            listenerService.listenPaiMaiRecord(contractAddress);      //部署成功则启动该合约的自动监听写库

            String id = transContractRequest.getId();
            ContractDO contractDO = new ContractDO();
            contractDO.setId(id);
            contractDO.setContractAddress(contractAddress);
            contractDO.setBeneficiary(_beneficiary);
            contractDO.setBiddingTime(transContractRequest.get_biddingTime());
            contractDO.setEndTime("endTime");
            contractDO.setContractStatus("auctioning");
            contractDO.setHighestBid("0");
            contractDO.setHighestBidder("0");
            contractMapper.addContract(contractDO);
        }
        return map;
    }

//    调用合约的  出价
    @Override
    public Map<String, Object> paiMaiBid(TransContractRequest transContractRequest) {
        String contractAddress = transContractRequest.get_contractAddress();
        String privateKey = transContractRequest.getPrivateKey();
        Credentials credentials = Credentials.create(privateKey);
        //获取全网平均gasprice
        BigInteger gasPrice = ethUtil.getMyGasPrice(web3j);
        BigInteger gasLimit = new BigInteger(transContractRequest.getGasLimit());
//        将出价转成wei单位
        BigInteger weiValue = Convert.toWei(transContractRequest.getMoney(), Convert.Unit.ETHER).toBigInteger();
//        加载合约对象
        PaiMai load = PaiMai.load(contractAddress, web3j, credentials, gasPrice, gasLimit);
        TransactionReceipt transactionReceipt=null;
        try {
            transactionReceipt = load.bid(weiValue).send();    //调用出价方法，返回合约收据
        } catch (Exception e) {
            e.printStackTrace();
        }
        HashMap<String, Object> map = new HashMap<>();
        if (transactionReceipt==null){
            map.put("code", "1");
            map.put("message", "请求失败，请检查后重新提交");
        }else {
            String transactionHash = transactionReceipt.getTransactionHash();
            map.put("code", "200");
            map.put("message", "ok");
            map.put("transactionHash", transactionHash);
        }
        return map;
    }

//    根据合约地址从库里查询拍卖明细
    @Override
    public List<ContractRecordDO> getContractRecordByContractAddress(String contractAddress) {
        return contractRecordMapper.getContractRecordByContractAddress(contractAddress);
    }

    //    查询当前拍卖交易明细，通过事件获取
    @Override
    public List<PaiMai.HighestBidIncreasedEventResponse> infoPaiMaiContract(String contractAddress) {
        PaiMai load = contractUtil.loadPaiMaiContract(contractAddress,web3j);
//        Request<?, EthGetTransactionReceipt> ethGetTransactionReceiptRequest = web3j.ethGetTransactionReceipt(contractAddress);
        TransactionReceipt transactionReceipt = load.getTransactionReceipt().get();
        List<PaiMai.HighestBidIncreasedEventResponse> highestBidIncreasedEvents = load.getHighestBidIncreasedEvents(transactionReceipt);
        return highestBidIncreasedEvents;
    }

    //    查询当前拍卖最终赢家,通过事件获取
    @Override
    public List<PaiMai.AuctionEndedEventResponse> endPaiMaiContract(String contractAddress) {
        PaiMai load = contractUtil.loadPaiMaiContract(contractAddress,web3j);
        TransactionReceipt transactionReceipt = load.getTransactionReceipt().get();
        List<PaiMai.AuctionEndedEventResponse> auctionEndedEvents = load.getAuctionEndedEvents(transactionReceipt);
        return auctionEndedEvents;
    }

//    查询拍卖结束时间
    @Override
    public Map<String, Object> paiMaiEndTime(String contractAddress) {
        PaiMai load = contractUtil.loadPaiMaiContract(contractAddress,web3j);
        Long paiMaiEndTime = null;
        try {
            paiMaiEndTime = load.auctionEndTime().send().longValue();
        } catch (Exception e) {
            e.printStackTrace();
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String endTime = dateFormat.format(new Date(paiMaiEndTime));
        HashMap<String, Object> map = new HashMap<>();
        map.put("endTime", endTime);
        return map;
    }

//    查询拍卖受益人
    @Override
    public Map<String, Object> paiMaiBeneficiary(String contractAddress) {
        PaiMai load = contractUtil.loadPaiMaiContract(contractAddress,web3j);
        String beneficiary = null;
        try {
            beneficiary = load.beneficiary().send();
        } catch (Exception e) {
            e.printStackTrace();
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("beneficiary", beneficiary);
        return map;
    }

//    拍卖当前最高出价人地址和出价
    @Override
    public Map<String, Object> paiMaiHighest(String contractAddress) {
        PaiMai load = contractUtil.loadPaiMaiContract(contractAddress,web3j);
        String highestBidder = null;
        String highestBid = null;
        try {
            highestBidder = load.highestBidder().send();
            highestBid = load.highestBid().send().toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("highestBidder", highestBidder);
        map.put("highestBid", highestBid);
        return map;
    }

//    出价人赎回金额
    @Override
    public Map<String, Object> paiMaiWithdraw(String privateKey, String contractAddress) {
        Credentials credentials = Credentials.create(privateKey);
        //获取全网平均gasprice
        BigInteger gasPrice = ethUtil.getMyGasPrice(web3j);
        BigInteger gasLimit = new BigInteger("500000");
        PaiMai load = PaiMai.load(contractAddress, web3j, credentials, gasPrice, gasLimit);
        TransactionReceipt transactionReceipt=null;
        try {
            transactionReceipt = load.withdraw().send();
        } catch (Exception e) {
            e.printStackTrace();
        }
        HashMap<String, Object> map = new HashMap<>();
        if (transactionReceipt==null){
            map.put("code", "1");
            map.put("message", "error");
        }else {
            String status = transactionReceipt.getStatus();
            map.put("code", "200");
            map.put("message", "ok");
            map.put("status", status);
        }
        return map;
    }

//    拍卖结束，拍卖人取回金额
    @Override
    public Map<String, Object> paiMaiAuctionClose(String privateKey, String contractAddress) {
        Credentials credentials = Credentials.create(privateKey);
        //获取全网平均gasprice
        BigInteger gasPrice = ethUtil.getMyGasPrice(web3j);
        BigInteger gasLimit = new BigInteger("500000");
        PaiMai load = PaiMai.load(contractAddress, web3j, credentials, gasPrice, gasLimit);
        TransactionReceipt transactionReceipt=null;
        try {
            transactionReceipt = load.auctionEnd().send();
        } catch (Exception e) {
            e.printStackTrace();
        }
        HashMap<String, Object> map = new HashMap<>();
        if (transactionReceipt==null){
            map.put("code", "1");
            map.put("message", "error");
        }else {
            String status = transactionReceipt.getStatus();
            map.put("code", "200");
            map.put("message", "ok");
            map.put("status", status);
        }
        return map;
    }
}
